package myJs

import myJs.Utils._
import org.scalajs.dom.{Element, _}
import scalatags.Text.all.{value, _}

import scala.collection.mutable
import scala.scalajs.js
import scala.scalajs.js.annotation.{JSExport, JSExportTopLevel}
import myJs.Implicits._
import myJs.myPkg._
import org.scalajs.dom.raw.{HTMLFormElement, XMLHttpRequest}
import org.scalajs.jquery.jQuery
import Tool._
import shared.VarTool

import scala.scalajs.js.JSConverters._
import scala.scalajs.js.JSON
import myJs.myPkg.jquery._
import org.scalajs.dom.ext.Ajax
import japgolly.scalajs.react.component.Scala.Unmounted
import myJs.components.DiagnoseComponent

import scala.collection.immutable.SeqMap
import scala.concurrent.ExecutionContext.Implicits.global
import scala.scalajs.js.Dynamic.{global => g}

/**
 * Created by yz on 2019/4/25
 */
@JSExportTopLevel("ReRunMission")
object ReRunMission {
  var index = 0
  var missionId = ""
  var component: Unmounted[Unit, DiagnoseComponent.State, DiagnoseComponent.Backend]#Mounted = _

  @JSExport("init")
  def init = {
    component = DiagnoseComponent.Component().renderIntoDOM(document.querySelector(s"#diagnose"))
    getCpuNum { cpuNum =>
      bootStrapValidator(cpuNum)
    }
    g.$("#form").bootstrapValidator("revalidateField", "missionName")
    fillMission
    NewMission.fillSpecies
    enrichLibSelect
    refreshDbId.map { x =>
      selectMission
    }

    NewMission.refreshReportHome()

    refreshTestOrder

    NewMission.refreshUnit

  }

  @JSExport("testOrderChange")
  def testOrderChange(y: Element) = {
    val myValue = $(y).find(">option:selected").`val`().toString
    testOrderChangeByValue(myValue)
  }

  def testOrderChangeByValue(myValue: String) = {
    val idMap = idNameTestPlatformMap.map { case (k, v) =>
      s"${k}${v}" -> k
    }
    val nameMap = idNameTestPlatformMap.map { case (k, v) =>
      s"${k}${v}" -> v
    }
    val id = idMap(myValue)
    val name = nameMap(myValue)
    Tool.getInputByName("reportHome.testOrderName").`val`(name)
    Tool.getInputByName("reportHome.testOrderId").`val`(id)
  }

  def refreshDbId = {
    val url = g.jsRoutes.controllers.MetaboDbController.getAllMetaboDb().url.toString
    Ajax.get(url = s"${url}").map { xhr =>
      val data = JSON.parse(xhr.responseText).toJArJDS.toList
      val array = (js.Dictionary("dbName" -> "默认库", "id" -> "0") :: (data)).map { dict =>
        js.Dictionary("text" -> dict("dbName"), "id" -> dict("id"))
      }
      val options = Select2Options.dictData(array.toJSArray)
      Tool.getInputByName("dbId").select2(options)
    }
  }

  var idNameTestPlatformMap = SeqMap[String, String]()

  def refreshTestOrder = {
    val url = g.jsRoutes.controllers.ToolController.getTestPlatform().url.toString
    Ajax.get(url = s"${url}").map { xhr =>
      val dict = JSON.parse(xhr.responseText).toJDS
      idNameTestPlatformMap = dict.toSeqMap
      val orders = idNameTestPlatformMap.map { case (k, v) => s"${k}${v}" }.toJSArray
      val options = Select2Options.placeholder("选择一个Test Order").data(orders)
      val name = Tool.getInputByName(VarTool.testOrderName).`val`().toString
      val id = Tool.getInputByName(VarTool.testOrderId).`val`().toString
      val t = (id, name)
      val orderRevMap = idNameTestPlatformMap.map { case (k, v) =>
        (k, v) -> s"${k}${v}"
      }
      val selectVal = orderRevMap.getOrElse(t, "")
      Tool.getInputByName("testOrder").select2(options)
      if (selectVal.nonEmpty) {
        Tool.getInputByName("testOrder").`val`(selectVal).select2().trigger("onchange")
      }
    }


  }

  def getCpuNum(f: Int => Unit) = {
    val url = g.jsRoutes.controllers.MissionController.getCpuNum().url.toString
    val ajaxSettings = JQueryAjaxSettings.url(s"${url}").`type`("get").async(false).success { (data, status, e) =>
      val rs = data
      val cpuNum = rs.toString.toInt
      f(cpuNum)
    }
    $.ajax(ajaxSettings)
  }

  def refreshConfig(missionId: String) = {
    val url = g.jsRoutes.controllers.MissionController.getConfig().url.toString
    val ajaxSettings = JQueryAjaxSettings.url(s"${url}?missionId=${missionId}").`type`("get").async(false).success { (data, status, e) =>
      val rs = data.asInstanceOf[js.Dictionary[String]]
      val species = rs("species")
      val speciesKind = NewMission.speciesData.map { case (kind, map) =>
        (kind -> map.keySet)
      }.flatMap { case (kind, specieses) =>
        specieses.map((_ -> kind))
      }
      val kind = speciesKind(species)
      $("#selectSpecies1").`val`(kind).trigger("onchange")
      $(":input[name='species']").`val`(species).trigger("onchange")
      fillByNames(rs)
      select2FillByNames(rs)
      fillByNameAndTriggers(rs, List("diagnoseIsExec"))
      fillByNameAndTriggers(rs)
      if (rs("hasExtraData").asInstanceOf[Boolean]) {
        $(s":input[name='cor.isCorExec']").attr("disabled", false)
        if (rs("hasCounfounder").asInstanceOf[Boolean]) {
          $(s":input[name='cor.isParCorExec']").attr("disabled", false)
        } else {
          $(s":input[name='cor.isParCorExec']").attr("disabled", true)
        }
      } else {
        $(s":input[name='cor.isCorExec']").attr("disabled", true)
        $(s":input[name='cor.isParCorExec']").`val`("F").attr("disabled", true)
      }
      val checkedNames = $(".checkedByOp").mapElems { y =>
        $(y).attr("name").toString
      }.toArray
      Tool.checkedByNames(rs, checkedNames)
      val libTypes = rs("pathway.libTypes").split(";").toJSArray
      $(":input[name='pathway.libTypes[]']").`val`(libTypes).trigger("change")
      val state = getState(rs)
      component.setState(state)
    }
    $.ajax(ajaxSettings)

  }

  def getState(rs: JDS) = {
    DiagnoseComponent.State(diagnoseIsExec = rs("diagnoseIsExec"), rfTop = rs("rfTop"), svmTop = rs("svmTop"),
      borutaAfterTopN = rs("borutaAfterTopN"),
      execCv = rs("execCv"),
      seed = rs("seed"),
      k = rs("k"))
  }

  def enrichLibSelect = {
    val data = VarTool.libTypeMap.map { case (fieldValue, text) =>
      js.Dictionary("id" -> fieldValue, "text" -> text)
    }.toJSArray
    val options = Select2Options.dictData(data).multiple(true)
    $(":input[name='pathway.libTypes[]']").select2(options)
    val array = js.Array("smpdb_pathway", "predicted")
    $(":input[name='pathway.libTypes[]']").`val`(array).select2()
  }

  def selectMission = {
    missionId = $(":input[name='hideMissionId']").`val`().toString
    if (missionId != "") {
      $(":input[name='missionId']").`val`(missionId).select2().trigger("onchange")
    }
  }

  def refreshMissionName(missionId: String) = {
    val url = g.jsRoutes.controllers.MissionController.getMissionById().url.toString
    Ajax.get(url = s"${url}?id=${missionId}").map { xhr =>
      val dict = JSON.parse(xhr.responseText).toJDS
      Tool.getInputByName("missionName").`val`(s"${dict("missionName")}_reRun")
      g.$("#form").bootstrapValidator("revalidateField", "missionName")
    }
  }

  def fillMission = {
    val url = g.jsRoutes.controllers.MissionController.getAllSuccessMissionNames().url.toString
    val ajaxSettings = JQueryAjaxSettings.url(url).`type`("get").async(false).success { (data, status, e) =>
      val rs = data.asInstanceOf[js.Array[String]]
      val options = Select2Options.placeholder("选择一个任务").data(rs)
      $(":input[name='missionId']").select2(options)
    }
    $.ajax(ajaxSettings)

  }

  @JSExport("missionChange")
  def missionChange(y: Element) = {
    val missionId = $(":input[name='missionId']").`val`().toString
    refreshMissionName(missionId)
    refreshConfig(missionId)
  }

  @JSExport("myRun")
  def myRun = {
    val bv = jQuery("#form").data("bootstrapValidator")
    bv.validate()
    val valid = bv.isValid().asInstanceOf[Boolean]
    if (valid) {
      $(":disabled").attr("disabled", false)
      val element = div(id := "content",
        span(id := "info", "正在运行",
          span(id := "progress", "。。。")), " ",
        img(src := "/assets/images/running2.gif", cls := "runningImage", width := 30, height := 20)
      ).render
      val layerOptions = LayerOptions.title(zhInfo).closeBtn(0).skin("layui-layer-molv").btn(js.Array())
      index = layer.alert(element, layerOptions)
      val url = g.jsRoutes.controllers.MissionController.reRunMission().url.toString
      val data = $(s"#form").serialize()
      val ajaxSettings = JQueryAjaxSettings.url(url).`type`("post").async(false).data(data).success { (data, status, e) =>
        val rs = data.asInstanceOf[js.Dictionary[js.Any]]
        layer.close(index)
        val valid = rs("valid").asInstanceOf[Boolean]
        if (valid) {
          window.location.href = g.jsRoutes.controllers.UserController.missionManageBefore().url.toString
        } else {
          g.swal("Error", rs.myGet("message"), "error")
        }
      }
      $.ajax(ajaxSettings)
    }
  }

  def bootStrapValidator(cpuNum: Int) = {
    val url = g.jsRoutes.controllers.MissionController.missionNameCheck().url.toString
    val maxNumber = Double.MaxValue
    val dict = js.Dictionary(
      "feedbackIcons" -> js.Dictionary(
        "valid" -> "glyphicon glyphicon-ok",
        "invalid" -> "glyphicon glyphicon-remove",
        "validating" -> "glyphicon glyphicon-refresh",
      ),
      "fields" -> js.Dictionary(
        "dataFile" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "代谢数据文件不能为空!"
            ),
            "file" -> js.Dictionary(
              "message" -> "代谢数据文件格式不正确!",
              "extension" -> "csv",
            ),
          )
        ),
        "groupFile" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "样品分组文件不能为空!"
            ),
            "file" -> js.Dictionary(
              "message" -> "样品分组文件格式不正确!",
              "extension" -> "csv",
            ),
          )
        ),
        "compareFile" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "比较配置文件不能为空!"
            ),
            "file" -> js.Dictionary(
              "message" -> "比较配置文件格式不正确!",
              "extension" -> "csv",
            ),
          )
        ),
        "sampleColorFile" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "分组颜色文件不能为空!"
            ),
            "file" -> js.Dictionary(
              "message" -> "分组颜色文件格式不正确!",
              "extension" -> "csv",
            ),
          )
        ),
        "missionName" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "任务名不能为空!"
            ),
            "remote" -> js.Dictionary(
              "message" -> "任务名已存在!",
              "extension" -> "csv",
              "url" -> url,
              "type" -> "POST",
              "delay" -> 1000
            ),
          )
        ),
        "diffMethod.pValue" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "p值阈值不能为空!"
            ),
            "numeric" -> js.Dictionary(
              "message" -> "p值阈值必须为数字!",
            ),
            "between" -> js.Dictionary(
              "min" -> 0,
              "max" -> 1,
              "message" -> "p值阈值必须在0到1之间！",
            ),
          )
        ),
        "diffMethod.fdr" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "fdr阈值不能为空!"
            ),
            "numeric" -> js.Dictionary(
              "message" -> "fdr阈值必须为数字!",
            ),
            "between" -> js.Dictionary(
              "min" -> 0,
              "max" -> 1,
              "message" -> "fdr阈值必须在0到1之间！",
            ),
          )
        ),
        "diffMethod.log2Fc" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "log2Fc阈值不能为空!"
            ),
            "numeric" -> js.Dictionary(
              "message" -> "log2Fc阈值必须为数字!",
            ),
          )
        ),
        VarTool.vipName -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "vip值阈值不能为空!"
            ),
            "numeric" -> js.Dictionary(
              "message" -> "vip值阈值必须为数字!",
            ),
          )
        ),
        VarTool.q2YName -> {
          val info = "Q2Y"
          js.Dictionary(
            "validators" -> js.Dictionary(
              "notEmpty" -> js.Dictionary(
                "message" -> s"${info}不能为空!"
              ),
              "numeric" -> js.Dictionary(
                "message" -> s"${info}必须为数字!",
              ),
            )
          )
        },
        VarTool.q2YBName -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "Q2Y纵截距最大值不能为空!"
            ),
            "numeric" -> js.Dictionary(
              "message" -> "Q2Y纵截距最大值必须为数字!",
            ),
          )
        ),
        "extraDataFile" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "file" -> js.Dictionary(
              "message" -> "额外数据矩阵文件格式不正确!",
              "extension" -> "csv",
            ),
          )
        ),
        "confounderFile" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "file" -> js.Dictionary(
              "message" -> "confounder矩阵文件格式不正确!",
              "extension" -> "csv",
            ),
          )
        ),
        "cor" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "cor阈值不能为空!"
            ),
            "numeric" -> js.Dictionary(
              "message" -> "cor阈值必须为数字!",
            ),
            "between" -> js.Dictionary(
              "min" -> 0,
              "max" -> 1,
              "message" -> "cor阈值必须在0到1之间！",
            ),
          )
        ),
        "corP" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "p值阈值不能为空!"
            ),
            "numeric" -> js.Dictionary(
              "message" -> "p值阈值必须为数字!",
            ),
            "between" -> js.Dictionary(
              "min" -> 0,
              "max" -> 1,
              "message" -> "p值阈值必须在0到1之间！",
            ),
          )
        ),
        "cor.fdr" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "fdr阈值不能为空!"
            ),
            "numeric" -> js.Dictionary(
              "message" -> "fdr阈值必须为数字!",
            ),
            "between" -> js.Dictionary(
              "min" -> 0,
              "max" -> 1,
              "message" -> "fdr阈值必须在0到1之间！",
            ),
          )
        ),
        "kwP" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "p值阈值不能为空!"
            ),
            "numeric" -> js.Dictionary(
              "message" -> "p值阈值必须为数字!",
            ),
            "between" -> js.Dictionary(
              "min" -> 0,
              "max" -> 1,
              "message" -> "p值阈值必须在0到1之间！",
            ),
          )
        ),
        "diffMethod.kwFdr" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "fdr阈值不能为空!"
            ),
            "numeric" -> js.Dictionary(
              "message" -> "fdr阈值必须为数字!",
            ),
            "between" -> js.Dictionary(
              "min" -> 0,
              "max" -> 1,
              "message" -> "fdr阈值必须在0到1之间！",
            ),
          )
        ),
        "diffTopN" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "top n不能为空!"
            ),
            "integer" -> js.Dictionary(
              "message" -> "top n必须为整数!",
            ),
            "between" -> js.Dictionary(
              "min" -> 1,
              "max" -> maxNumber,
              "message" -> "top n必须大于0！",
            ),
          )
        ),
        "borutaAfterTopN" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "Boruta执行后top n不能为空!"
            ),
            "integer" -> js.Dictionary(
              "message" -> "Boruta执行后top n必须为整数!",
            ),
            "between" -> js.Dictionary(
              "min" -> 2,
              "max" -> maxNumber,
              "message" -> "Boruta执行后top n必须大于1！",
            ),
          )
        ),
        "missionId" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "必须选择一个任务!"
            )
          )
        ),
        "coef" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "coef不能为空!"
            ),
            "numeric" -> js.Dictionary(
              "message" -> "coef必须为数字!",
            ),
          )
        ),
        "knn" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "k值不能为空!"
            ),
            "integer" -> js.Dictionary(
              "message" -> "k值必须为数字!",
            ),
            "between" -> js.Dictionary(
              "min" -> 1,
              "max" -> maxNumber,
              "message" -> "k值必须大于0！",
            ),
          )
        ),
        "rfTop" -> {
          val info = "RandomForest top n"
          js.Dictionary(
            "validators" -> js.Dictionary(
              "notEmpty" -> js.Dictionary(
                "message" -> s"${info}不能为空!"
              ),
              "integer" -> js.Dictionary(
                "message" -> s"${info}必须为整数!",
              ),
              "between" -> js.Dictionary(
                "min" -> 2,
                "max" -> maxNumber,
                "message" -> s"${info}必须大于1！",
              ),
            )
          )
        },
        "svmTop" -> {
          val info = "SVM top n"
          js.Dictionary(
            "validators" -> js.Dictionary(
              "notEmpty" -> js.Dictionary(
                "message" -> s"${info}不能为空!"
              ),
              "integer" -> js.Dictionary(
                "message" -> s"${info}必须为整数!",
              ),
              "between" -> js.Dictionary(
                "min" -> 2,
                "max" -> maxNumber,
                "message" -> s"${info}必须大于1！",
              ),
            )
          )
        },
        "seed" -> {
          val info = "Seed"
          js.Dictionary(
            "validators" -> js.Dictionary(
              "notEmpty" -> js.Dictionary(
                "message" -> s"${info}不能为空!"
              ),
              "integer" -> js.Dictionary(
                "message" -> s"${info}必须为整数!",
              ),
            )
          )
        },
        "threadNum" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "线程数不能为空！"
            ),
            "integer" -> js.Dictionary(
              "message" -> "线程数必须为整数！",
            ),
            "between" -> js.Dictionary(
              "min" -> 1,
              "max" -> cpuNum,
              "message" -> s"线程数必须大于0且小于等于${cpuNum}(服务器可用最大cpu)！",
            ),
          )
        ),

      )
    )
    g.$("#form").bootstrapValidator(dict)

  }


}
